﻿namespace Jhong.OWINSession.InProcess
{
    using System;

    internal class SessionCache : ISessionOpera
    {
        private readonly static CircularCollection<string, Session> _cache = new CircularCollection<string, Session>();

        private static object _lock = new object();

        public Session GetSession(string sessionID)
        {
            lock (_lock)
            {
                return _cache[sessionID];
            }
        }

        public void SetSession(string sessionID, Session session)
        {
            lock (_lock)
            {
                _cache[sessionID] = session;
            }
        }

        private static Func<string, Session, bool> _recoverFunc = (sid, s) =>
        {
            if (DateTime.Now > s.DeathTime) return true;
            return false;
        };

        private static int _expiredCheckSecond = 30;

        private static DateTime _nextExpiredCheckTime = DateTime.Now.AddSeconds(_expiredCheckSecond);

        public void SetTimeOut(string sessionID)
        {
            var currSession = this.GetSession(sessionID);
            currSession.DeathTime = DateTime.Now.AddMinutes(OWINSessionOption.OSOption.SessionExpiredMinute.Value);
            this.SetSession(sessionID, currSession);

            this.CheckCheck();
        }

        private void CheckCheck()
        {
            lock (_lock)
            {
                if (DateTime.Now <= _nextExpiredCheckTime) return;
                var currTime = DateTime.Now;
                _cache.Recover((sid, s) =>
                {
                    return s.DeathTime < currTime;
                });
                _nextExpiredCheckTime = DateTime.Now.AddMinutes(_expiredCheckSecond);
            }
        }

        public bool CheckExists(string sessionID)
        {
            lock (_lock)
            {
                return _cache.Contains(new System.Collections.Generic.KeyValuePair<string, Session>(sessionID, null));
            }
        }
    }
}